﻿using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace RaGE
{
    public class EList
    {
        public string listName;
        public byte[] listOffset;
        public string[] elementFields;
        public string[] elementTypes;
        public object[][] elementValues;

        public string GetValue(int elementIndex, int fieldIndex)
        {
            string result;

            if (fieldIndex > -1)
            {
                var obj = elementValues[elementIndex][fieldIndex];
                var text = elementTypes[fieldIndex];

                switch (text)
                {
                    case "int16":
                        result = Convert.ToString((short)obj);
                        return result;
                    case "int32":
                        result = Convert.ToString((int)obj);
                        return result;
                    case "int64":
                        result = Convert.ToString((int)obj);
                        return result;
                    case "float":
                        result = Convert.ToString((float)obj);
                        return result;
                    case "double":
                        result = Convert.ToString((double)obj);
                        return result;
                }

                if (text.Contains("byte:"))
                {
                    var value = (byte[])obj;
                    result = BitConverter.ToString(value);
                    return result;
                }

                if (text.Contains("wstring:"))
                {
                    var encoding = Encoding.GetEncoding("Unicode");
                    var separator = new[] { '\0' };

                    result = encoding.GetString((byte[])obj).Split(separator)[0];
                    return result;
                }

                if (text.Contains("string:"))
                {
                    var encoding2 = Encoding.GetEncoding("GBK");
                    var separator2 = new[] { '\0' };

                    result = encoding2.GetString((byte[])obj).Split(separator2)[0];
                    return result;
                }
            }

            result = "";
            return result;
        }

        public void SetValue(int elementIndex, int fieldIndex, string value)
        {
            var text = elementTypes[fieldIndex];

            switch (text)
            {
                case "int16":
                    elementValues[elementIndex][fieldIndex] = Convert.ToInt16(value);
                    break;

                case "int32":
                    elementValues[elementIndex][fieldIndex] = Convert.ToInt32(value);
                    break;

                case "int64":
                    elementValues[elementIndex][fieldIndex] = Convert.ToInt64(value);
                    break;

                case "float":
                    elementValues[elementIndex][fieldIndex] = Convert.ToSingle(value);
                    break;

                case "double":
                    elementValues[elementIndex][fieldIndex] = Convert.ToDouble(value);
                    break;

                default:
                    if (text.Contains("byte:"))
                    {
                        var array = value.Split(new[] { '-' });
                        var array2 = new byte[Convert.ToInt32(text.Substring(5))];

                        for (var i = 0; i < array.Length; i++)
                            array2[i] = Convert.ToByte(array[i], 16);

                        elementValues[elementIndex][fieldIndex] = array2;
                    }

                    else if (text.Contains("wstring:"))
                    {
                        var encoding = Encoding.GetEncoding("Unicode");
                        var array = new byte[Convert.ToInt32(text.Substring(8))];
                        var bytes = encoding.GetBytes(value);

                        Array.Copy(bytes, array, array.Length > bytes.Length ? bytes.Length : array.Length);

                        elementValues[elementIndex][fieldIndex] = array;
                    }

                    else if (text.Contains("string:"))
                    {
                        var encoding = Encoding.GetEncoding("GBK");
                        var array = new byte[Convert.ToInt32(text.Substring(7))];
                        var bytes = encoding.GetBytes(value);

                        Array.Copy(bytes, array, array.Length > bytes.Length ? bytes.Length : array.Length);

                        elementValues[elementIndex][fieldIndex] = array;
                    }
                    break;
            }
        }

        public string GetType(int fieldIndex)
        {
            return fieldIndex > -1 ? elementTypes[fieldIndex] : "";
        }

        public void RemoveItem(int itemIndex)
        {
            var array = new object[elementValues.Length - 1][];

            Array.Copy(elementValues, 0, array, 0, itemIndex);
            Array.Copy(elementValues, itemIndex + 1, array, itemIndex, array.Length - itemIndex);

            elementValues = array;
        }

        public void AddItem(object[] itemValues)
        {
            Array.Resize(ref elementValues, elementValues.Length + 1);
            elementValues[elementValues.Length - 1] = itemValues;
        }

        public void ExportItem(string file, int index)
        {
            var streamWriter = new StreamWriter(file, false, Encoding.Unicode);

            for (var i = 0; i < elementTypes.Length; i++)
                streamWriter.WriteLine(elementFields[i] + "(" + elementTypes[i] + ")=" + GetValue(index, i));

            streamWriter.Close();
        }

        public void ImportItem(string file, int index)
        {
            var streamReader = new StreamReader(file, Encoding.Unicode);

            for (var i = 0; i < elementTypes.Length; i++)
            {
                var separator = new[] { '=' };
                var readLine = streamReader.ReadLine();

                if (readLine != null) SetValue(index, i, readLine.Split(separator)[1]);
            }

            streamReader.Close();
        }

        public ArrayList JoinElements(EList newList, int listID, [MarshalAs(UnmanagedType.U1)] bool addNew,
            [MarshalAs(UnmanagedType.U1)] bool backupNew, [MarshalAs(UnmanagedType.U1)] bool replaceChanged,
            [MarshalAs(UnmanagedType.U1)] bool backupChanged, [MarshalAs(UnmanagedType.U1)] bool removeMissing,
            [MarshalAs(UnmanagedType.U1)] bool backupMissing, string dirBackupNew, string dirBackupChanged, string dirBackupMissing)
        {
            var array = newList.elementValues;
            var arrayList = new ArrayList();

            for (var i = 0; i < elementValues.Length; i++)
            {
                Application.DoEvents();
                var flag = false;

                for (var j = 0; j < array.Length; j++)
                    if (GetValue(i, 0) == newList.GetValue(j, 0))
                        flag = true;

                if (flag) continue;

                if (dirBackupMissing != null && Directory.Exists(dirBackupMissing))
                {
                    var num = listID;
                    ExportItem(dirBackupMissing + "\\List_" + num.ToString(CultureInfo.InvariantCulture) + "_Item_" + GetValue(i, 0) + ".txt", i);
                }

                if (removeMissing)
                {
                    var num2 = (int)elementValues[i][0];
                    arrayList.Add("- MISSING ITEM (*removed): " + num2.ToString(CultureInfo.InvariantCulture));
                    RemoveItem(i);
                    i--;
                }
                else
                {
                    var num3 = (int)elementValues[i][0];
                    arrayList.Add("- MISSING ITEM (*not removed): " + num3.ToString(CultureInfo.InvariantCulture));
                }
            }

            for (var k = 0; k < array.Length; k++)
            {
                Application.DoEvents();
                var flag = false;

                for (var l = 0; l < elementValues.Length; l++)
                {
                    if (GetValue(l, 0) != newList.GetValue(k, 0)) continue;

                    flag = true;

                    if (elementValues[l].Length != newList.elementValues[k].Length)
                        arrayList.Add("<> DIFFERENT ITEM (*not replaced, invalid amount of values): " + GetValue(l, 0));

                    else
                    {
                        for (var m = 0; m < elementValues[l].Length; m++)
                        {
                            if (GetValue(l, m) == newList.GetValue(k, m)) continue;

                            if (backupChanged && Directory.Exists(dirBackupChanged))
                            {
                                var num4 = listID;
                                ExportItem(dirBackupChanged + "\\List_" + num4.ToString(CultureInfo.InvariantCulture) + "_Item_" +
                                    GetValue(l, 0) + ".txt", l);
                            }

                            if (replaceChanged)
                            {
                                arrayList.Add("<> DIFFERENT ITEM (*replaced): " + GetValue(l, 0));
                                elementValues[l] = newList.elementValues[k];
                            }
                            else
                                arrayList.Add("<> DIFFERENT ITEM (*not replaced): " + GetValue(l, 0));
                            break;
                        }
                    }
                    break;
                }

                if (flag) continue;

                if (backupNew && Directory.Exists(dirBackupNew))
                {
                    var num5 = listID;
                    newList.ExportItem(dirBackupNew + "\\List_" + num5.ToString(CultureInfo.InvariantCulture) +
                        "_Item_" + newList.GetValue(k, 0) + ".txt", k);
                }

                if (addNew)
                {
                    AddItem(array[k]);
                    arrayList.Add("+ NEW ITEM (*added): " + GetValue(elementValues.Length - 1, 0));
                }
                else
                    arrayList.Add("+ NEW ITEM (*not added): " + GetValue(elementValues.Length - 1, 0));
            }
            return arrayList;
        }
    }
}
